package com.xlh.openai.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.plexpt.chatgpt.ChatGPT;
import com.plexpt.chatgpt.ChatGPTStream;
import com.plexpt.chatgpt.entity.chat.ChatCompletion;
import com.plexpt.chatgpt.entity.chat.ChatCompletionResponse;
import com.plexpt.chatgpt.entity.chat.Message;
import com.plexpt.chatgpt.util.Proxys;
import com.xlh.openai.entity.ConfigEntity;
import com.xlh.openai.entity.WechatUserEntity;
import com.xlh.openai.exception.ServiceException;
import com.xlh.openai.listener.OpenAISSEEventListener;
import com.xlh.openai.service.AIService;
import com.xlh.openai.service.ChatRecordsService;
import com.xlh.openai.service.ConfigService;
import com.xlh.openai.service.WechatUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.*;

@Slf4j
@Service
public class OpenAiChatServiceImpl implements AIService {

    @Autowired
    private WechatUserService wechatUserService;

    // 存储用户对话的聊天记录
    private static Map<Integer, List<Message>> conversationMap = new HashMap<>();

    private static Map<String, String> map = new HashMap<>();
    /**
     * 队列
     */
    private static LinkedList<Message> linkedList = new LinkedList<>();

    @Autowired
    private ChatRecordsService chatRecordsService;

    @Value("${token}")
    private String token;

    @Value("${knife4j.production}")
    private Boolean production;

    @Autowired
    private ConfigService configService;


    /**
     * 聊天
     * @param prompt
     * @return
     */
    public String chat(String prompt, Double temperature){

        ConfigEntity config = configService.getOne(new QueryWrapper<ConfigEntity>().lambda().eq(ConfigEntity::getKey, ConfigService.FOREIGN_INTERFACE));
        if(config.getValue().equals("1") == false){
            throw new ServiceException("对外端口暂时关闭！");
        }
        if(StrUtil.isBlank(prompt)){
            throw new ServiceException("问题不能为空！");
        }
        if(ObjectUtil.isNull(temperature)){
            temperature = 0.9;
        }
        if(temperature.compareTo(0d) == -1
                || temperature.compareTo(2d) == 1){
            throw new ServiceException("temperature参数需在0~2之间！");
        }

        // 代理
        // Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
        //国内需要代理 国外不需要
        ChatGPT chatGPT = ChatGPT.builder()
                .apiKey(token)
                .timeout(900)
        //.proxy(proxy)
                .apiHost("https://api.openai.com/")
                .build()
                .init();

        ChatCompletion chatCompletion = ChatCompletion.builder()
                .model(ChatCompletion.Model.GPT_3_5_TURBO.getName())
                .messages(Lists.newArrayList(Message.ofSystem(prompt)))
                .maxTokens(1000)
                .temperature(temperature)
                .build();

        ChatCompletionResponse response = chatGPT.chatCompletion(chatCompletion);
        Message answerMessage = response.getChoices().get(0).getMessage();
        String question = prompt + answerMessage.getContent();
        Long tokens = Long.valueOf(question.getBytes().length);
        Integer userId = -1;
        String conversationId = "student_train";
        String answer = answerMessage.getContent();
        chatRecordsService.saveConversation(userId, conversationId, prompt,answer, tokens);

        return answerMessage.getContent();
    }


    /**
     * 聊天
     * @param prompt
     * @return
     */
    public String chat(Integer userId, String prompt){

        Integer conversationLength = 4;
        List<Message> userMessages = conversationMap.get(userId);
        if(userMessages == null){
            userMessages = new ArrayList<>();
        }
        //国内需要代理 国外不需要
        ChatGPT chatGPT = ChatGPT.builder()
                .apiKey(token)
                .timeout(900)
                .apiHost("https://api.openai.com/")
                .build()
                .init();

        if(userMessages.size() > conversationLength){
            // 截取到第六个对话
            userMessages = CollectionUtil.sub( userMessages, (userMessages.size() - conversationLength), userMessages.size());
        }
        userMessages.add(Message.ofSystem(prompt));
        ChatCompletion chatCompletion = ChatCompletion.builder()
                .model(ChatCompletion.Model.GPT_3_5_TURBO.getName())
                .messages(userMessages)
                .maxTokens(1000)
                .temperature(0.9)
                .build();
        ChatCompletionResponse response = chatGPT.chatCompletion(chatCompletion);
        Message answerMessage = response.getChoices().get(0).getMessage();
        userMessages.add(answerMessage);
        conversationMap.put(userId, userMessages);

        return answerMessage.getContent();
    }

    /**
     * 调用GPT接口
     * @param prompt
     * @param openId
     * @return
     */
    @Override
    public String chat(String prompt, String openId) {
        String answers = "您当前的问答次数已用尽，请购买次数后再使用！";
        // 查询当前用户剩余次数
        WechatUserEntity wechatUser = wechatUserService.getByOpenId(openId);
        if(wechatUser.getQuestionTime() > 0){
            try {
                WechatUserEntity userEntity = wechatUserService.getByOpenId(openId);
                answers = chat(userEntity.getId(), prompt);
                wechatUserService.consumeTime(userEntity);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("调用chatGpt异常！", e);
                answers = "小码正在努力为您解析！";
            }
        }
        return answers;
    }

    @Override
    public SseEmitter chatStreamQuestion( Integer userId, String prompt,
                                          String parentMessageId,
                                          List<Message> messages, String conversationId )  {
        ChatGPTStream chatGPTStream;
        // 非生产环境使用测试账号
        chatGPTStream = ChatGPTStream.builder()
                .timeout(600)
                .apiKey(token)
                .apiHost("https://api.openai.com/")
                .build()
                .init();
        SseEmitter sseEmitter = new SseEmitter(-1L);
        OpenAISSEEventListener openSourceListener = new OpenAISSEEventListener(sseEmitter);
        openSourceListener.setParentMessageId(parentMessageId);
        openSourceListener.setConversationId(conversationId);
        openSourceListener.setPrompt(prompt);
        openSourceListener.setUserId(userId);
        openSourceListener.setChatRecordsService(chatRecordsService);

        messages.add(Message.of(prompt));
        chatGPTStream.streamChatCompletion(messages, openSourceListener);

        return sseEmitter;
    }
}